"use strict";
var models = require('./../models');
var co = require('co');
var LineFit = require('./LineFit');

/** 
 * 线路拟合帮助类
 */
class SurveyFitLine {
    constructor() {
        this.manualLines = [];//人工测量线路组合
        this.designLines = [];//设计坐标线路组合
        this.surveyLines = [];//自动化测量线路组合
        this.surveyPointCache = [];//自动化测量点的缓存,达到标准后自动从这里拟合线段
    }
    
  
    
    /** 
     * 根据给定的里程,获取该里程上的坐标
     * @return {Object} {x,y,z,e,n,h}
     */
    _getCoorAtMile(mile, lines) {
        var line = lines.filter(function (lineItem) {
            return mile >= lineItem.startPoint.mileage && mile <= lineItem.endPoint.mileage;
        })[0];
        if (!line) return null;//如果不在里程区间范围内的话,就返回null
        var mileDiff = mile - line.startPoint.mileage;
        var coor = line.getCoorAtMile(mileDiff);
        return coor;
    }
    
    /** 
     * 根据给定的里程,获取里程上的坐标
     * 先在人工实测的线路中搜寻,查询不到再去自动化拟合的线路中搜寻
     */
    getCoorAtMile(mile) {
        var coor = this._getCoorAtMile(mile, this.manualLines);
        if (coor) return coor;
        else {//超出了人工观测的范围,那么就要从自动化拟合的线路中获取了
            coor = this._getCoorAtMile(mile, this.surveyLines);
        }
        return coor;
    }
    
    
    /** 
     * 根据给定的里程,获取拟合的直线或实测的直线
     */
    getLineAtMile(mile) {
        if (mile < 0) mile = 0; //强行不能为负
        var line = this.manualLines.find(function (item) {
            return mile >= item.startPoint.mileage && mile <= item.endPoint.mileage;
        });
        if (line) return line;
        line = this.surveyLines.find(function (item) {
            return mile >= item.startPoint.mileage && mile <= item.endPoint.mileage;
        });
        if (line) return line;
        return this.surveyLines[this.surveyLines.length - 1];
    }

    
    /** 
     * 根据给定的里程,返回设计直线上的坐标
     * @param {number} mile 里程
     * @return {object} 坐标
     */
    getDesignCoorAtMile(mile) {
        var coor = this._getCoorAtMile(mile, this.designLines);
        if (coor) return coor;
        else {
            var line = this.designLines[this.designLines.length - 1];
            var mileDiff = mile - line.startPoint.mileage;
            coor = line.getCoorAtMile(mileDiff);
            return coor;
        }
    }
    
    /** 
     * 添加自动化点
     * param {object} point 测量数据 {e,n,h,mileage}
     */
    addSurveyPoint(point) {
        this.surveyPointCache.push(point);
    }
    
    /** 处理缓存下来的pf隧道中心点,对其进行拟合,并将原始数据存入数据库 */
    processPointCache() {
        var _this = this;
        return co(function* () {
            if (_this.surveyPointCache.length <= 2) return;
            var line = LineFit.Line2d.line2dFit(_this.surveyPointCache);
            _this.surveyLines.push(line);
            var pt = _this.surveyPointCache[_this.surveyPointCache.length - 1];
            var maxNo = yield _this._getSurveyCenterMaxNo(pt.prjId);
            var no = maxNo + 1;
            _this.surveyPointCache.forEach(function (pt) {
                pt.no = no;
            });
            yield models.SurveyCenter.bulkCreate(_this.surveyPointCache);
            _this.surveyPointCache = [];
            _this.addSurveyPoint(pt);//为了首尾衔接,把最后一个点放到下一个组的第一个
        }).catch(function (err) {
            console.log(err.stack);
        });
    }


    _getSurveyCenterMaxNo(prjId) {
        return co(function* () {
            var results = yield models.sequelize.query('select max(No) as no from SurveyCenter where PrjId = ' + prjId, { type: models.sequelize.QueryTypes.SELECT });
            if (!results[0].no) return 0;
            else return results[0].no;
        });
    }
    
    
    /** 
     * 从数据库读取人工和实测线路
     */
    static getLineFromDb(prjId) {
        return co(function* () {
            var fitLine = new SurveyFitLine();
            fitLine.manualLines = yield SurveyFitLine.generateFixLine(prjId, 'ManualCenter');
            fitLine.designLines = yield SurveyFitLine.generateFixLine(prjId, 'DesignCenter');
            fitLine.surveyLines = yield SurveyFitLine.generateSurveyLine(prjId);
            if (fitLine.surveyLines.length > 0) {
                //把最后一个点加入现有的缓存中
                fitLine.surveyPointCache.push(fitLine.surveyLines[fitLine.surveyLines.length - 1].endPoint);
            }
            return fitLine;
        });
    }
    
    /** 
     * 从数据库的数据拟合出自动观测线路
     */
    static generateSurveyLine(prjId) {
        var lines = [];
        return co(function* () {
            var surveyCenters = yield models.SurveyCenter.findAll({
                where: {
                    $and: {
                        prjId: prjId,
                        no: {
                            $ne: null
                        },
                        e: {
                            $ne: null
                        }
                    }
                },
                order: [["Id", "ASC"], ['No', 'ASC']]
            });
            var no = null;
            var tempPointArray = [];
            for (var i = 0; i < surveyCenters.length; i++) {
                var pt = surveyCenters[i];
                if (pt.no === null || pt.e === null) continue;
                //group,以no相同为一组,no最后一点与no+1第一点重合,这是约定
                if (pt.no !== no) {
                    if (tempPointArray.length) {
                        //获取了一组pf点的坐标,准备开始拟合
                        var line = LineFit.Line2d.line2dFit(tempPointArray);
                        lines.push(line);
                    }
                    no = pt.no;
                    tempPointArray = [];
                } else {
                    tempPointArray.push(pt);
                }
            }
            return lines;
        });
    }
    
    
    /** 
   * 从数据库中读取人工/设计线路,作为起始的参考中心线
   * @return {Array<Line>} 人工/设计拟合的线路
   */
    static generateFixLine(prjId, lineType) {
        var lines = [];
        return co(function* () {
            var targetCenters = yield models[lineType].findAll({
                where: {
                    prjId: prjId
                }
            });
            for (var i = 0; i < targetCenters.length - 1; i++) {
                var center = targetCenters[i];//第一个中心
                var centerNext = targetCenters[i + 1];//下一个中心
                var line = LineFit.Line2d.createLine2d(center, centerNext);
                line.startMile = center.mileage;
                line.endMile = centerNext.mileage;
                lines.push(line);
            }
            return lines;
        });
    }

}

module.exports = SurveyFitLine;